package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.user.modules.models.Goods;
import cn.wizzer.app.user.modules.models.UserExchange;
import cn.wizzer.app.user.modules.models.enums.BizTypeEnum;
import cn.wizzer.app.user.modules.models.enums.ExchangeEnum;
import cn.wizzer.app.user.modules.models.vo.UserExchangeVo;
import cn.wizzer.app.user.modules.services.account.ExchangeService;
import cn.wizzer.app.user.modules.services.GoodsService;
import cn.wizzer.app.user.modules.services.account.UserAccountRecordService;
import cn.wizzer.framework.base.Result;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.Id;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.commons.lang3.ArrayUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = ExchangeService.class)
public class ExchangeServiceImpl extends BaseServiceImpl<UserExchange> implements ExchangeService {

    public ExchangeServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private CommonDBService dbService;

    @Inject
    @Reference
    private GoodsService goodsService;

    @Inject
    @Reference
    private UserAccountRecordService userAccountRecordService;

    @Override
    public Pagination listPage(Integer pageNumber, int pageSize, String searchKeyword, String[] searchDate, ExchangeEnum status) {
        Sql sql = Sqls.create("select g.name,g.cover_pic,e.remark,e.price,e.id,e.status,e.delFlag,e.opAt,e.createAt,a.receiverName,a.receiverPhone,a.addr " +
                "from user_exchange e " +
                "left join user_address a on e.address_id = a.id " +
                "left join goods g on e.goods_id = g.id " +
                "$condition ");
        Sql countSql = Sqls.create("select count(1) from user_exchange e " +
                "$condition ");
        Cnd cnd = Cnd.where("e.delFlag", "=", 0);
        if (status != null) {
            cnd.and("e.status", "=", status);
        }
        if (Strings.isNotBlank(searchKeyword)) {
            searchKeyword = "%" + searchKeyword + "%";
            cnd.and(Cnd.exps("e.receiverName", "like", searchKeyword)
                    .or("e.receiverPhone", "like", searchKeyword));
        }
        if (ArrayUtils.isNotEmpty(searchDate)) {
            cnd.and("e.createAt", ">=", Times.d2TS(Times.D(searchDate[0])));
            cnd.and("e.createAt", "<=", Times.d2TS(Times.D(searchDate[1])));
        }
        sql.setCondition(cnd);
        sql.appendSourceSql("order by e.createAt desc");
        countSql.setCondition(cnd);
        return dbService.listPage(UserExchangeVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    @Override
    public Pagination listPage(Integer pageNumber, int pageSize, ExchangeEnum status, String userId) {
        Sql sql = Sqls.create("select g.name,g.cover_pic,e.id,e.user_id,e.remark,e.price,e.status,e.opAt, e.logistics_no, e.logistics_company, e.order_no " +
                "from user_exchange e " +
                "left join goods g on e.goods_id = g.id " +
                "$condition ");
        Sql countSql = Sqls.create("select count(1) from user_exchange e " +
                "$condition ");
        Cnd cnd = Cnd.where("e.user_id", "=", userId)
                .and("e.delFlag", "=", 0);
        if(status != null){
            cnd.and("e.status", "=", status);
        }
        sql.setCondition(cnd);
        sql.appendSourceSql("order by e.opAt desc");
        countSql.setCondition(cnd);
        return dbService.listPage(UserExchangeVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void add(UserExchange userExchange) {
        // 查询商品价格
        Goods goods = goodsService.fetch(userExchange.getGoodsId());
        userExchange.setPrice(goods.getPrice());
        // 设置订单状态为已付款。余额不足会回滚，不会插入。
        userExchange.setStatus(ExchangeEnum.PAID);
        // 设置订单创建时间
        userExchange.setCreateAt(Times.getTS());
        //设置订单号
        userExchange.setOrderNo(Id.createOrderNo());
        // 校验上架状态
        if (goods.isDisabled()) {
            Result.breakWith("商品已经下架");
        }
        // 目前下单时数量不可选，数量都是1。所以校验库存是否小于1.
        if (goods.getStock() < 1) {
            Result.breakWith("库存不足");
        }
        // 更新库存数量
        goods.setStock(goods.getStock() - 1);
        // 乐观锁
        goodsService.updateWithVersion(goods);

        this.insert(userExchange);
        userAccountRecordService.add(userExchange.getUserId(), userExchange.getPrice(), BizTypeEnum.EXCHANGE, userExchange.getId());
    }

    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void cancel(String id) {
        UserExchange fetch = this.fetch(id);
        if (fetch.getStatus()== ExchangeEnum.CANCELED) {
            Result.breakWith("该订单已取消");
        }
        //订单状态
        this.update(Chain.make("status", ExchangeEnum.CANCELED)
                .add("opAt", Times.getTS()), Cnd.where("id", "=", id));
        //库存
        Goods good = goodsService.fetch(fetch.getGoodsId());
        good.setStock(good.getStock()+1);
        goodsService.updateWithVersion(good);
        //余额
        this.userAccountRecordService.add(fetch.getUserId(),fetch.getPrice(),BizTypeEnum.EXCHANGE_BACK,fetch.getId());
    }


}
